﻿#include "ctp_api_market.h"
#include <filesystem>
#include <time_utils.hpp>
#include <params.hpp>
#include <log_wapper.hpp>

// 构造函数：初始化行情 API 对象并加载相关配置
// 参数：
// - id_excg_map: 交易所 ID 映射
// - config: 行情参数配置
ctp_api_market::ctp_api_market(const std::shared_ptr<std::unordered_map<std::string, std::string>>& id_excg_map, const params& config) noexcept
    : asyn_actual_market(id_excg_map)
    , _md_api(nullptr)
    , _reqid(0)
    , _process_mutex(_mutex)
    , _is_inited(false)
{
    // 从配置中读取必要的参数
    try
    {
        _front_addr = config.get<std::string>("front");  // 前置地址
        _broker_id = config.get<std::string>("broker");  // 经纪商 ID
        _userid = config.get<std::string>("userid");     // 用户 ID
        _password = config.get<std::string>("passwd");   // 用户密码
    }
    catch (...)
    {
        // 记录配置错误
        LOG_ERROR("ctp_api_market config error ");
    }

    // 加载 CTP 行情动态库
    _market_handle = dll_helper::load_library("thostmduserapi_se");
    if (_market_handle)
    {
#ifdef _WIN32
#    ifdef _WIN64
        const char* creator_name = "?CreateFtdcMdApi@CThostFtdcMdApi@@SAPEAV1@PEBD_N1@Z"; // Windows 64 位创建函数符号名
#    else
        const char* creator_name = "?CreateFtdcMdApi@CThostFtdcMdApi@@SAPAV1@PBD_N1@Z";  // Windows 32 位创建函数符号名
#    endif
#else
        const char* creator_name = "_ZN15CThostFtdcMdApi15CreateFtdcMdApiEPKcbb";  // Linux 创建函数符号名
#endif
        // 从动态库中获取创建函数指针
        _ctp_creator = (market_creator)dll_helper::get_symbol(_market_handle, creator_name);
    }
    else
    {
        // 记录加载错误
        LOG_ERROR("ctp_api_trader thosttraderapi_se load error ");
    }
}

// 析构函数：释放行情 API 资源
ctp_api_market::~ctp_api_market() noexcept
{
    // 释放动态库资源
    dll_helper::free_library(_market_handle);
    _market_handle = nullptr;
}

// 登录函数：用于登录行情服务器
// 返回值：登录成功返回 true，否则返回 false
bool ctp_api_market::login() noexcept
{
    // 构建保存行情流水文件的路径
    char path_buff[64] = {0};
    sprintf(path_buff, "md_flow/%s/%s/", _broker_id.c_str(), _userid.c_str());
    if (!std::filesystem::exists(path_buff))
    {
        // 创建保存行情文件的目录
        std::filesystem::create_directories(path_buff);
    }

    // 创建行情 API 实例并注册回调 SPI
    _md_api = _ctp_creator(path_buff, false, false);
    _md_api->RegisterSpi(this);
    _md_api->RegisterFront((char*)_front_addr.c_str());
    _md_api->Init();
    
    // 等待登录响应完成
    _process_signal.wait(_process_mutex);
    _is_inited = true;
    return true;
}

// 登出函数：用于登出行情服务器并清理资源
void ctp_api_market::logout() noexcept
{
    // 重置请求 ID
    _reqid = 0;
    _id_excg_map->clear();
    if (_md_api)
    {
        // 取消注册 SPI 并释放 API 实例
        _md_api->RegisterSpi(nullptr);
        // _md_api->Join();
        _md_api->Release();
        _md_api = nullptr;
    }
    _is_inited = false;
}

// 错误响应回调
void ctp_api_market::OnRspError(CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast) noexcept
{
    if (pRspInfo)
    {
        LOG_ERROR("Error:%d->%s", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
    }
}

// 连接成功回调：用于触发登录操作
void ctp_api_market::OnFrontConnected() noexcept
{
    LOG_INFO("Connected : %s", _front_addr.c_str());
    do_userlogin();  // 发送登录请求
}

// 登录响应回调：处理登录结果
void ctp_api_market::OnRspUserLogin(CThostFtdcRspUserLoginField* pRspUserLogin, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast) noexcept
{
    if (pRspInfo)
    {
        LOG_DEBUG("UserLogin : %d -> %s", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
    }
    if (bIsLast)
    {
        LOG_INFO("UserLogin : Market data server logined, {%s} {%s}", pRspUserLogin->TradingDay, pRspUserLogin->UserID);
        do_subscribe();  // 订阅行情数据
        if (!_is_inited)
        {
            _process_signal.notify_all();
        }
    }
}

// 登出响应回调
void ctp_api_market::OnRspUserLogout(CThostFtdcUserLogoutField* pUserLogout, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast) noexcept
{
    if (pRspInfo)
    {
        LOG_DEBUG("UserLogout : %d -> %s", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
    }
}

// 连接断开回调
void ctp_api_market::OnFrontDisconnected(int nReason) noexcept
{
    LOG_INFO("FrontDisconnected : Reason -> %d", nReason);
}

// 深度行情数据回调
void ctp_api_market::OnRtnDepthMarketData(CThostFtdcDepthMarketDataField* pDepthMarketData) noexcept
{
    if (pDepthMarketData == nullptr)
    {
        return;
    }

    PROFILE_INFO(pDepthMarketData->InstrumentID);
    LOG_DEBUG("MarketData =", pDepthMarketData->InstrumentID, pDepthMarketData->LastPrice, pDepthMarketData->UpdateTime, pDepthMarketData->UpdateMillisec);
    
    // 处理交易所 ID
    const char* excg_id = pDepthMarketData->ExchangeID;
    auto excg_it = _id_excg_map->find(pDepthMarketData->InstrumentID);
    if (excg_it != _id_excg_map->end())
    {
        excg_id = excg_it->second.c_str();
    }

    PROFILE_DEBUG(pDepthMarketData->InstrumentID);
    
    // 构建行情 tick 数据
    tick_info tick(
        code_t(pDepthMarketData->InstrumentID, excg_id),
        make_daytm(pDepthMarketData->UpdateTime, static_cast<uint32_t>(pDepthMarketData->UpdateMillisec)),
        pDepthMarketData->OpenPrice,
        pDepthMarketData->ClosePrice,
        pDepthMarketData->HighestPrice,
        pDepthMarketData->LowestPrice,
        pDepthMarketData->LastPrice,
        pDepthMarketData->PreSettlementPrice,
        pDepthMarketData->Volume,
        std::atoi(pDepthMarketData->TradingDay),
        pDepthMarketData->OpenInterest,
        {
            std::make_pair(pDepthMarketData->BidPrice1, pDepthMarketData->BidVolume1),
            std::make_pair(pDepthMarketData->BidPrice2, pDepthMarketData->BidVolume2),
            std::make_pair(pDepthMarketData->BidPrice3, pDepthMarketData->BidVolume3),
            std::make_pair(pDepthMarketData->BidPrice4, pDepthMarketData->BidVolume4),
            std::make_pair(pDepthMarketData->BidPrice5, pDepthMarketData->BidVolume5)
        },
        {
            std::make_pair(pDepthMarketData->AskPrice1, pDepthMarketData->AskVolume1),
            std::make_pair(pDepthMarketData->AskPrice2, pDepthMarketData->AskVolume2),
            std::make_pair(pDepthMarketData->AskPrice3, pDepthMarketData->AskVolume3),
            std::make_pair(pDepthMarketData->AskPrice4, pDepthMarketData->AskVolume4),
            std::make_pair(pDepthMarketData->AskPrice5, pDepthMarketData->AskVolume5)
        }
    );

    PROFILE_DEBUG(pDepthMarketData->InstrumentID);
    // 触发行情接收事件
    this->fire_event(market_event_type::MET_TickReceived, tick);
    PROFILE_DEBUG(pDepthMarketData->InstrumentID);
}

// 订阅行情响应回调
void ctp_api_market::OnRspSubMarketData(CThostFtdcSpecificInstrumentField* pSpecificInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast) noexcept
{
    if (pRspInfo)
    {
        LOG_INFO("SubMarketData : code -> %d %s", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
    }
}

// 取消订阅行情响应回调
void ctp_api_market::OnRspUnSubMarketData(CThostFtdcSpecificInstrumentField* pSpecificInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast) noexcept
{
    if (pRspInfo)
    {
        LOG_INFO("UnSubMarketData : code -> %d %s", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
    }
}

// 执行登录请求
void ctp_api_market::do_userlogin() noexcept
{
    if (_md_api == nullptr)
    {
        return;
    }

    // 构建登录请求
    CThostFtdcReqUserLoginField req;
    memset(&req, 0, sizeof(req));
    strcpy(req.BrokerID, _broker_id.c_str());
    strcpy(req.UserID, _userid.c_str());
    strcpy(req.Password, _password.c_str());
    
    // 发送登录请求
    int iResult = _md_api->ReqUserLogin(&req, ++_reqid);
    if (iResult != 0)
    {
        LOG_ERROR("do_userlogin : %d", iResult);
    }
}

// 执行订阅行情请求
void ctp_api_market::do_subscribe() noexcept
{
    char* id_list[500];  // 临时数组存储合约 ID 列表
    int num = 0;
    for (auto& it : *_id_excg_map)
    {
        id_list[num] = const_cast<char*>(it.first.c_str());
        num++;
        if (num == 500)
        {
            // 批量订阅行情
            _md_api->SubscribeMarketData(id_list, num);
            num = 0;
        }
    }
    if (num > 0)
    {
        // 订阅剩余的行情
        _md_api->SubscribeMarketData(id_list, num);
    }
}

// 执行取消订阅行情请求
void ctp_api_market::do_unsubscribe(const std::vector<code_t>& code_list) noexcept
{
    char* id_list[500];  // 临时数组存储合约 ID 列表
    int num = 0;
    for (size_t i = 0; i < code_list.size(); i++)
    {
        id_list[num] = const_cast<char*>(code_list[i].get_id());
        num++;
        if (num == 500)
        {
            // 批量取消订阅行情
            _md_api->UnSubscribeMarketData(id_list, num);
            num = 0;
        }
    }
    if (num > 0)
    {
        // 取消订阅剩余的行情
        _md_api->UnSubscribeMarketData(id_list, num);
    }
}

// 订阅指定的行情
void ctp_api_market::subscribe(const std::set<code_t>& code_list) noexcept
{
    for (auto& it : code_list)
    {
        // 更新交易所 ID 映射表
        (*_id_excg_map)[it.get_id()] = it.get_excg();
    }
    // 执行订阅操作
    do_subscribe();
}

// 取消订阅指定的行情
void ctp_api_market::unsubscribe(const std::set<code_t>& code_list) noexcept
{
    std::vector<code_t> delete_code_list;
    for (auto& it : code_list)
    {
        auto n = _id_excg_map->find(it.get_id());
        if (n != _id_excg_map->end())
        {
            // 从映射表中移除并加入取消订阅列表
            delete_code_list.emplace_back(it);
            _id_excg_map->erase(n);
        }
    }
    // 执行取消订阅操作
    do_unsubscribe(delete_code_list);
}
